﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Globalization;
using System.Threading;
using System.Net;

namespace LiveResults.OnlineLib
{
    public class LiveServer : IDisposable
    {

        public delegate void LogMsgHandler(string msg);
        public event LogMsgHandler LogMsg;

        Thread uploader = null;
        string m_Key;
        string m_Password;
        bool runUploader = false;
        public LiveServer(string key, string password)
        {
            m_Key = key;
            m_Password = password;

            runUploader = true;
            uploader = new Thread(new ThreadStart(uploaderThread));
            uploader.Start();

        }

        List<object> uploadQueue = new List<object>();

        public void QueueUpload(object o)
        {
            lock (uploadQueue)
            {
                uploadQueue.Add(o);
            }
        }

        /// <summary>
        /// The main uploader thread that handles all uploads......
        /// </summary>
        void uploaderThread()
        {
            while (runUploader)
            {
                while (uploadQueue.Count > 0)
                {
                    object o = null;
                    lock (uploadQueue)
                    {
                        o = uploadQueue[0];
                    }
                    if (o is OnlineClass)
                    {
                        string message;
                        if (UploadClass(o as OnlineClass, out message))
                        {
                            lock (uploadQueue)
                            {
                                uploadQueue.RemoveAt(0);
                            }
                        }
                        else
                        {
                            ///Something went wrong... break out for one loop..
                            LogMsgHandler h = LogMsg;
                            if (h != null)
                                h(message);
                            break;
                        }
                    }
                    else if (o is OnlineResult)
                    {
                        string message;
                        if (UploadResult(o as OnlineResult, out message))
                        {
                            lock (uploadQueue)
                            {
                                uploadQueue.RemoveAt(0);
                            }
                        }
                        else
                        {
                            ///Something went wrong... break out for one loop..
                            LogMsgHandler h = LogMsg;
                            if (h != null)
                                h(message);
                            break;
                        }
                    }
                }
                Thread.Sleep(100);
            }
        }

        private bool UploadResult(OnlineResult onlineResult, out string message)
        {
            try
            {
                message = null;
                List<string> controlCodes= new List<string>();
                List<string> controlSplits = new List<string>();
                for (int i = 0; i< onlineResult.SplitControls.Count; i++)
                {
                    controlSplits.Add(onlineResult.SplitTimes[i].ToString());
                    controlCodes.Add(onlineResult.SplitControls[i].ToString());
                }
                string url = string.Format(onlineAPIUrl + "Competitions/{0}/SetResult?firstname={1}&lastname={2}&classname={3}&totaltime={4}&status={5}&password={6}&splitcontrols={7}&splittimes={8}&clubname={9}&id={10}",
                    m_Key, onlineResult.FirstName, onlineResult.LastName, onlineResult.ClassName, onlineResult.TotalTime, onlineResult.Status, m_Password, string.Join(",", controlCodes.ToArray()), string.Join(",", controlSplits.ToArray()), onlineResult.ClubName, onlineResult.DbID);
                XDocument doc = XDocument.Load(url);
                var c = (from r in doc.Elements() select new ResponseStatus { Status = (string)r.Attribute("status"), Message = (r.Attribute("message") == null ? "" : (string)r.Attribute("message")) }).FirstOrDefault();

                if (c == null)
                    return false;
                else if (c.Status == "OK")
                    return true;
                else
                {
                    message = c.Message;
                    return false;
                }
            }
            catch (Exception ee)
            {
                message = ee.Message;
                return false;
            }
        }

        /// <summary>
        /// Uploads a Class to the onlineserver
        /// </summary>
        /// <param name="onlineClass"></param>
        /// <returns></returns>
        private bool UploadClass(OnlineClass onlineClass, out string message)
        {
            try
            {
                message = null;
                List<string> controlNames = new List<string>();
                List<string> controlCodes = new List<string>();
                foreach (RadioControl rc in onlineClass.Controls)
                {
                    controlNames.Add(rc.Name);
                    controlCodes.Add(rc.Code.ToString());
                }
                XDocument doc = XDocument.Load(string.Format(onlineAPIUrl + "Competitions/{0}/SetClass?name={1}&id={2}&password={3}&controlids={4}&controlnames={5}", m_Key, onlineClass.ClassName, onlineClass.ClassID, m_Password, string.Join(",", controlCodes.ToArray()), string.Join(",", controlNames.ToArray())));
                var c = (from r in doc.Elements() select new ResponseStatus { Status = (string)r.Attribute("status"), Message = (r.Attribute("message") == null ? "" : (string)r.Attribute("message")) }).FirstOrDefault();

                if (c == null)
                    return false;
                else if (c.Status == "OK")
                    return true;
                else
                {
                    message = c.Message;
                    return false;
                }
            }
            catch (Exception ee)
            {
                message = ee.Message;
                return false;

            }
        }

        static string onlineAPIUrl = "http://live-ol.appspot.com/API/";
        //static string onlineAPIUrl = "http://192.168.0.191:8080/API/";

        public static List<Competition> GetAvailableCompeitiotns()
        {
            XDocument doc = XDocument.Load(onlineAPIUrl + "Competitions");
            var comps = from c in doc.Descendants("competition")
                        select new Competition { Name = (string)c.Attribute("name"), Organizer = (string)c.Attribute("organizer"), Id = (string)c.Attribute("id"), Date = DateTime.ParseExact((string)c.Attribute("date"), "yyyy-MM-dd", CultureInfo.InvariantCulture) };

            return comps.ToList();
        }

        public static bool ValidatePassword(string EventID, string password, out string message)
        {
            try
            {
                message = null;
                XDocument doc = XDocument.Load(string.Format(onlineAPIUrl + "Competitions/{0}/ValidatePassword?password={1}", EventID, password));
                var c = (from r in doc.Elements() select new ResponseStatus { Status = (string)r.Attribute("status"), Message = (r.Attribute("message") == null ? "" : (string)r.Attribute("message")) }).FirstOrDefault();

                if (c == null)
                    return false;
                else if (c.Status == "OK")
                    return true;
                else
                {
                    message = c.Message;
                    return false;
                }
            }
            catch (Exception ee)
            {
                message = ee.Message;
                return false;
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            runUploader = false;
        }

        #endregion
    }
}
